/* grytole@gmail.com 30-Jun-2012 */

#define lsdllib_c
#define LUA_LIB

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_image.h>

#define SDLSURFACE "sdl_surface"

#define DEFAULT_WINDOW_TITLE "SDLua"

#define SDL_FLAGS SDL_INIT_VIDEO

static SDL_Surface *m_surface = NULL;

/* isok, errmsg = sdl.init( {w, h, bpp}, title ) */
static int sdl_init( lua_State *L )
{
  const char *window_title = NULL;
  int window_width = 0;
  int window_height = 0;
  int window_bpp = 0;

  if( 0 == lua_istable( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "First parameter must be a table." );
    return 2;
  }

  if( 0 != SDL_Init( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  if( 0 != TTF_Init() )
  {
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, TTF_GetError() );
    return 2;
  }

  if( IMG_INIT_PNG != IMG_Init( IMG_INIT_PNG ) )
  {
    TTF_Quit();
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, IMG_GetError() );
    return 2;
  }

  if( 0 == lua_isstring( L, 2 ) )
  {
    SDL_WM_SetCaption( DEFAULT_WINDOW_TITLE, DEFAULT_WINDOW_TITLE );
  }
  else
  {
    window_title = lua_tostring( L, 2 );
    SDL_WM_SetCaption( window_title, window_title );
  }

  lua_getfield( L, 1, "w" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, "Window width not a number." );
    return 2;
  }

  window_width = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 1, "h" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, "Window height not a number." );
    return 2;
  }

  window_height = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 1, "bpp" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, "Window bpp not a number." );
    return 2;
  }

  window_bpp = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  m_surface = SDL_SetVideoMode( window_width, window_height, window_bpp, SDL_HWSURFACE | SDL_DOUBLEBUF );
  if( NULL == m_surface )
  {
    IMG_Quit();
    TTF_Quit();
    SDL_Quit();
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  return 1;
}

/* isok, errmsg = sdl.quit() */
static int sdl_quit( lua_State *L )
{
  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  IMG_Quit();
  TTF_Quit();
  SDL_Quit();

  lua_pushboolean( L, true );
  return 1;
}

/* isok, errmsg = sdl.flip() */
static int sdl_flip( lua_State *L )
{
  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 != SDL_Flip( m_surface ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  return 1;
}

/* isok, errmsg = sdl.delay( msec ) */
static int sdl_delay( lua_State *L )
{
  int msec = 0;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_isnumber( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Parameter must be a number." );
    return 2;
  }

  msec = lua_tointeger( L, 1 );

  SDL_Delay( msec );

  lua_pushboolean( L, true );
  return 1;
}

/* isok, errmsg = sdl.shot( filename ) */
static int sdl_shot( lua_State *L )
{
  const char *filename = NULL;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_isstring( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Parameter must be a string." );
    return 2;
  }

  filename = lua_tostring( L, 1 );

  if( 0 != SDL_SaveBMP( m_surface, filename ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  return 1;
}

/* isok, retval = sdl.image( filename ) */
static int sdl_image( lua_State *L )
{
  SDL_Surface *image_surface = NULL;
  SDL_Surface **retval = NULL;
  const char *filename = NULL;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_isstring( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Parameter must be a string." );
    return 2;
  }

  filename = lua_tostring( L, 1 );

  image_surface = IMG_Load( filename );
  if( NULL == image_surface )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, IMG_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  retval = (SDL_Surface**)lua_newuserdata( L, sizeof( SDL_Surface* ) );
  *retval = image_surface;
  luaL_setmetatable( L, SDLSURFACE );
  return 2;
}

/* isok, retval = sdl.text( text, {font, size}, {r, g, b} ) */
static int sdl_text( lua_State *L )
{
  TTF_Font *font = NULL;
  SDL_Surface *text_surface = NULL;
  SDL_Surface **retval = NULL;
  const char *text = NULL;
  const char *filename = NULL;
  int size = 0;
  SDL_Color color;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_isstring( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "First parameter must be a string." );
    return 2;
  }

  if( 0 == lua_istable( L, 2 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Second parameter must be a table." );
    return 2;
  }

  if( 0 == lua_istable( L, 3 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Third parameter must be a table." );
    return 2;
  }

  text = lua_tostring( L, 1 );

  lua_getfield( L, 2, "font" );
  if( 0 == lua_isstring( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Font filename not a string." );
    return 2;
  }

  filename = lua_tostring( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 2, "size" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Font size not a number." );
    return 2;
  }

  size = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 3, "r" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Red value not a number." );
    return 2;
  }

  color.r = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 3, "g" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Green value not a number." );
    return 2;
  }

  color.g = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 3, "b" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Blue value not a number." );
    return 2;
  }

  color.b = lua_tointeger( L, -1 );
  lua_pop( L, 1 );
  
  font = TTF_OpenFont( filename, size );
  if( NULL == font )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, TTF_GetError() );
    return 2;
  }

  text_surface = TTF_RenderText_Blended( font, text, color );
  if( NULL == text_surface )
  {
    TTF_CloseFont( font );
    lua_pushboolean( L, false );
    lua_pushstring( L, TTF_GetError() );
    return 2;
  }

  TTF_CloseFont( font );

  lua_pushboolean( L, true );
  retval = (SDL_Surface**)lua_newuserdata( L, sizeof( SDL_Surface* ) );
  *retval = text_surface;
  luaL_setmetatable( L, SDLSURFACE );
  return 2;
}

/* isok, retval = sdl.fill( {w, h}, {r, g, b, a} ) */
static int sdl_fill( lua_State *L )
{
  SDL_Surface *fill_surface = NULL;
  SDL_Surface **retval = NULL;
  SDL_Rect rect;
  SDL_Color color;
  int alpha = 0;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_istable( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "First parameter must be a table." );
    return 2;
  }

  if( 0 == lua_istable( L, 2 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Second parameter must be a table." );
    return 2;
  }

  lua_getfield( L, 1, "w" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Rect width not a number." );
    return 2;
  }
  rect.w = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 1, "h" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false ); 
    lua_pushstring( L, "Rect height not a number." );
    return 2;
  } 
  rect.h = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 2, "r" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Red value not a number." );
    return 2;
  }
  color.r = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 2, "g" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Green value not a number." );
    return 2;
  }
  color.g = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 2, "b" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Blue value not a number." );
    return 2;
  }
  color.b = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  lua_getfield( L, 2, "a" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    alpha = 0;
  }
  else
  {
    alpha = lua_tointeger( L, -1 );
  }
  lua_pop( L, 1 );

  fill_surface = SDL_CreateRGBSurface( SDL_HWSURFACE,
                                       rect.w, rect.h, m_surface->format->BitsPerPixel,
                                       m_surface->format->Rmask,
                                       m_surface->format->Gmask,
                                       m_surface->format->Bmask,
                                       m_surface->format->Amask );
  if( NULL == fill_surface )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  if( 0 != SDL_FillRect( fill_surface,
                         NULL,
                         SDL_MapRGBA( m_surface->format, color.r, color.g, color.b, alpha ) ) )
  {
    SDL_FreeSurface( fill_surface );
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  retval = (SDL_Surface**)lua_newuserdata( L, sizeof( SDL_Surface* ) );
  *retval = fill_surface;
  luaL_setmetatable( L, SDLSURFACE );
  return 2;
}

/* isok, errmsg = sdl.blit( srcsurface, {x, y, w, h}, dstsurface, {x, y} ) */
static int sdl_blit( lua_State *L )
{
  SDL_Surface *src_surface = NULL;
  SDL_Surface *dst_surface = NULL;
  SDL_Surface **tmp_surface_ptr = NULL;
  SDL_Rect src_rect;
  SDL_Rect dst_rect;
  SDL_Rect *src_rect_ptr = NULL;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  if( 0 == lua_isuserdata( L, 1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "First parameter must be a userdata." );
    return 2;
  }

  if( ( 0 == lua_istable( L, 2 ) ) && ( 0 == lua_isnil( L, 2 ) ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Second parameter must be a table or nil." );
    return 2;
  }

  if( ( 0 == lua_isuserdata( L, 3 ) ) && ( 0 == lua_isnil( L, 3 ) ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "First parameter must be a userdata or nil." );
    return 2;
  }

  if( 0 == lua_istable( L, 4 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Second parameter must be a table." );
    return 2;
  }

  tmp_surface_ptr = (SDL_Surface**)lua_touserdata( L, 1 );
  if( NULL == tmp_surface_ptr )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Src surface not a userdata." );
    return 2;
  }

  if( NULL == *tmp_surface_ptr )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Src surface is invalid." );
    return 2;
  }
  src_surface = *tmp_surface_ptr;

  if( 0 != lua_istable( L, 2 ) )
  {
    lua_getfield( L, 2, "x" );
    if( 0 == lua_isnumber( L, -1 ) )
    {
      lua_pushboolean( L, false );
      lua_pushstring( L, "Src rect xpos not a number." );
      return 2;
    }
    src_rect.x = lua_tointeger( L, -1 );
    lua_pop( L, 1 );

    lua_getfield( L, 2, "y" );
    if( 0 == lua_isnumber( L, -1 ) )
    {
      lua_pushboolean( L, false );
      lua_pushstring( L, "Src rect ypos not a number." );
      return 2;
    }
    src_rect.y = lua_tointeger( L, -1 );
    lua_pop( L, 1 );

    lua_getfield( L, 2, "w" );
    if( 0 == lua_isnumber( L, -1 ) )
    {
      lua_pushboolean( L, false );
      lua_pushstring( L, "Src rect width not a number." );
      return 2;
    }
    src_rect.w = lua_tointeger( L, -1 );
    lua_pop( L, 1 );

    lua_getfield( L, 2, "h" );
    if( 0 == lua_isnumber( L, -1 ) )
    {
      lua_pushboolean( L, false );
      lua_pushstring( L, "Src rect height not a number." );
      return 2;
    }
    src_rect.h = lua_tointeger( L, -1 );
    lua_pop( L, 1 );

    src_rect_ptr = &src_rect;
  }

  tmp_surface_ptr = (SDL_Surface**)lua_touserdata( L, 3 );
  if( NULL == *tmp_surface_ptr )
  {
    dst_surface = m_surface;
  }
  else
  {
    dst_surface = *tmp_surface_ptr;
  }

  tmp_surface_ptr = (SDL_Surface**)lua_touserdata( L, 3 );
  if( NULL == tmp_surface_ptr )
  {
    dst_surface = m_surface;
  }
  else
  {
    if( NULL == *tmp_surface_ptr )
    {
      dst_surface = m_surface;
    }
    else
    {
      dst_surface = *tmp_surface_ptr;
    }
  }

  lua_getfield( L, 4, "x" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Dst rect xpos not a number." ); 
    return 2;
  } 
  dst_rect.x = lua_tointeger( L, -1 );
  lua_pop( L, 1 );
  
  lua_getfield( L, 4, "y" );
  if( 0 == lua_isnumber( L, -1 ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "Dst rect ypos not a number." );
    return 2;
  }
  dst_rect.y = lua_tointeger( L, -1 );
  lua_pop( L, 1 );

  if( 0 != SDL_BlitSurface( src_surface, src_rect_ptr, dst_surface, &dst_rect ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, SDL_GetError() );
    return 2;
  }

  lua_pushboolean( L, true );
  return 1;
}

/* isok, retval = sdl.ticks() */
static int sdl_ticks( lua_State *L )
{
  unsigned int ticks = 0;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  ticks = SDL_GetTicks();

  lua_pushboolean( L, true );
  lua_pushinteger( L, ticks );
  return 2;
}

/* isok, retval = sdl.events() */
static int sdl_events( lua_State *L )
{
  SDL_Event event;
  int index = 1;

  if( SDL_FLAGS != SDL_WasInit( SDL_FLAGS ) )
  {
    lua_pushboolean( L, false );
    lua_pushstring( L, "SDL not initialised." );
    return 2;
  }

  lua_pushboolean( L, true );
  lua_newtable( L );
  while( SDL_PollEvent( &event ) )
  {
    switch( event.type )
    {
      case SDL_QUIT:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "quit" );
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      case SDL_KEYDOWN:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "keydown" );
        lua_settable( L, -3 );
        lua_pushstring( L, "key" );
        lua_pushstring( L, SDL_GetKeyName( event.key.keysym.sym ) );
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      case SDL_KEYUP:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "keyup" );
        lua_settable( L, -3 );
        lua_pushstring( L, "key" );
        lua_pushstring( L, SDL_GetKeyName( event.key.keysym.sym ) );
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      case SDL_MOUSEMOTION:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "mousemotion" );
        lua_settable( L, -3 );
        lua_pushstring( L, "x" );
        lua_pushinteger( L, event.motion.x );
        lua_settable( L, -3 );
        lua_pushstring( L, "y" );
        lua_pushinteger( L, event.motion.y );
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      case SDL_MOUSEBUTTONDOWN:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "mousebuttondown" );
        lua_settable( L, -3 );
        lua_pushstring( L, "button" );
        switch( event.button.button )
        {
          case SDL_BUTTON_LEFT:
          {
            lua_pushstring( L, "left" );
            break;
          }

          case SDL_BUTTON_MIDDLE:
          {
            lua_pushstring( L, "middle" );
            break;
          }

          case SDL_BUTTON_RIGHT:
          {
            lua_pushstring( L, "right" );
            break;
          }

          case SDL_BUTTON_WHEELUP:
          {
            lua_pushstring( L, "wheelup" );
            break;
          }

          case SDL_BUTTON_WHEELDOWN:
          {
            lua_pushstring( L, "wheeldown" );
            break;
          }

          default:
          {
            lua_pushstring( L, "unknown" );
            break;
          }
        }
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      case SDL_MOUSEBUTTONUP:
      {
        lua_pushinteger( L, index );

        lua_newtable( L );
        lua_pushstring( L, "type" );
        lua_pushstring( L, "mousebuttonup" );
        lua_settable( L, -3 );
        lua_pushstring( L, "button" );
        switch( event.button.button )
        {
          case SDL_BUTTON_LEFT:
          {
            lua_pushstring( L, "left" );
            break;
          }

          case SDL_BUTTON_MIDDLE:
          {
            lua_pushstring( L, "middle" );
            break;
          }

          case SDL_BUTTON_RIGHT:
          {
            lua_pushstring( L, "right" );
            break;
          }

          case SDL_BUTTON_WHEELUP:
          {
            lua_pushstring( L, "wheelup" );
            break;
          }

          case SDL_BUTTON_WHEELDOWN:
          {
            lua_pushstring( L, "wheeldown" );
            break;
          }

          default:
          {
            lua_pushstring( L, "unknown" );
            break;
          }
        }
        lua_settable( L, -3 );

        lua_settable( L, -3 );
        index++;
        break;
      }

      default:
      {
        break;
      }
    }
  }
  return 2;
}

static int mt_sdl_gc( lua_State *L )
{
  SDL_Surface **surface = NULL;

  surface = (SDL_Surface**)lua_touserdata( L, 1 );
  if( NULL != surface )
  {
    if( NULL != *surface )
    {
      SDL_FreeSurface( *surface );
    }
  }

  return 0;
}

static int mt_sdl_tostring( lua_State *L )
{
  SDL_Surface **surface = NULL;

  surface = (SDL_Surface**)lua_touserdata( L, 1 );
  if( NULL == surface )
  {
    lua_pushstring( L, "Not a userdata" );
    return 1;
  }
  if( NULL == *surface )
  {
    lua_pushstring( L, "SDL_Surface (nil)" );
    return 1;
  }

  lua_pushfstring( L, "SDL_Surface (%p)", *surface );
  return 1;
}

static int mt_sdl_index( lua_State *L )
{
  SDL_Surface **surface = NULL;
  const char *key = NULL;
  size_t keylen = 0;

  surface = (SDL_Surface**)lua_touserdata( L, 1 );
  if( NULL == surface )
  {
    lua_pushnil( L );
    return 1;
  }
  if( NULL == *surface )
  {
    lua_pushnil( L );
    return 1;
  }

  key = lua_tolstring( L, 2, &keylen );
  if( NULL == key )
  {
    lua_pushnil( L );
  }

  if( 0 == strncmp( key, "w", keylen ) )
  {
    lua_pushinteger( L, (*surface)->w );
    return 1;
  }

  if( 0 == strncmp( key, "h", keylen ) )
  {
    lua_pushinteger( L, (*surface)->h );
    return 1;
  }

  lua_pushnil( L );
  return 1;
}

static const luaL_Reg sdllib[] = {
  { "init",   sdl_init },
  { "quit",   sdl_quit },
  { "flip",   sdl_flip },
  { "delay",  sdl_delay },
  { "shot",   sdl_shot },
  { "image",  sdl_image },
  { "text",   sdl_text },
  { "fill",   sdl_fill },
  { "blit",   sdl_blit },
  { "ticks",  sdl_ticks },
  { "events", sdl_events },
  { NULL,     NULL }
};

static const luaL_Reg mt_sdlsurface[] = {
  { "__gc",       mt_sdl_gc },
  { "__tostring", mt_sdl_tostring },
  { "__index",    mt_sdl_index },
  { NULL,         NULL }
};

LUAMOD_API int luaopen_sdl( lua_State *L )
{
  luaL_newlib( L, sdllib );

  luaL_newmetatable( L, SDLSURFACE );
  luaL_setfuncs( L, mt_sdlsurface, 0 );
  lua_pop( L, 1 );

  return 1;
}

/* eof */
